index.ts ➔ buildStateHistory   F
last analyzed

Complexity

Conditions 15

Size

Total Lines 30
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 26
dl 0
loc 30
rs 2.9998
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like index.ts ➔ buildStateHistory often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import type { Entity } from '@shopware-ag/admin-extension-sdk/es/data/_internals/Entity';
2
import type EntityCollection from '@shopware-ag/admin-extension-sdk/es/data/_internals/EntityCollection';
3
import type { PropType } from 'vue';
4
import type RepositoryType from 'src/core/data/repository.data';
5
import type CriteriaType from 'src/core/data/criteria.data';
6
import template from './sw-order-state-history-modal.html.twig';
7
8
/**
9
 * @package checkout
10
 */
11
12
const { Component, Mixin } = Shopware;
13
const { Criteria } = Shopware.Data;
14
15
interface StateMachineHistoryData {
16
    order: Entity<'state_machine_state'>,
17
    transaction: Entity<'state_machine_state'>,
18
    delivery: Entity<'state_machine_state'>,
19
    createdAt: string,
20
    user?: {
21
        username: string
22
    },
23
    entity: string,
24
}
25
26
interface CombinedStates {
27
    order: Entity<'state_machine_state'>,
28
    ['order_transaction']: Entity<'state_machine_state'>,
29
    ['order_delivery']: Entity<'state_machine_state'>,
30
}
31
32
// eslint-disable-next-line sw-deprecation-rules/private-feature-declarations
33
export default Component.wrapComponentConfig({
34
    template,
35
36
    inject: [
37
        'repositoryFactory',
38
        'stateStyleDataProviderService',
39
    ],
40
41
    mixins: [
42
        Mixin.getByName('notification'),
43
    ],
44
45
    props: {
46
        order: {
47
            type: Object as PropType<Entity<'order'>>,
48
            required: true,
49
        },
50
        isLoading: {
51
            type: Boolean,
52
            required: true,
53
        },
54
    },
55
56
    data(): {
57
        dataSource: StateMachineHistoryData[],
58
        statesLoading: boolean,
59
        limit: number,
60
        page: number,
61
        total: number,
62
        steps: number[],
63
        } {
64
        return {
65
            dataSource: [],
66
            statesLoading: true,
67
            limit: 10,
68
            page: 1,
69
            total: 0,
70
            steps: [5, 10, 25],
71
        };
72
    },
73
74
    computed: {
75
        stateMachineHistoryRepository(): RepositoryType<'state_machine_history'> {
76
            return this.repositoryFactory.create('state_machine_history');
77
        },
78
79
        stateMachineHistoryCriteria(): CriteriaType {
80
            const criteria = new Criteria(this.page, this.limit);
81
82
            const entityIds = [
83
                this.order.id,
84
                ...(this.order.transactions ?? []).map((transaction) => {
85
                    return transaction.id;
86
                }),
87
                ...(this.order.deliveries ?? []).map((delivery) => {
88
                    return delivery.id;
89
                }),
90
            ];
91
92
            criteria.addFilter(
93
                Criteria.equalsAny(
94
                    'state_machine_history.entityId.id',
95
                    entityIds,
96
                ),
97
            );
98
            criteria.addFilter(
99
                Criteria.equalsAny(
100
                    'state_machine_history.entityName',
101
                    ['order', 'order_transaction', 'order_delivery'],
102
                ),
103
            );
104
            criteria.addAssociation('fromStateMachineState');
105
            criteria.addAssociation('toStateMachineState');
106
            criteria.addAssociation('user');
107
            criteria.addSorting({
108
                field: 'state_machine_history.createdAt',
109
                order: 'ASC',
110
                naturalSorting: false,
111
            });
112
113
            return criteria;
114
        },
115
116
        columns(): Array<{property: string, label: string}> {
117
            return [
118
                { property: 'createdAt', label: this.$tc('sw-order.stateHistoryModal.column.createdAt') },
119
                { property: 'entity', label: this.$tc('sw-order.stateHistoryModal.column.entity') },
120
                { property: 'user', label: this.$tc('sw-order.stateHistoryModal.column.user') },
121
                { property: 'transaction', label: this.$tc('sw-order.stateHistoryModal.column.transaction') },
122
                { property: 'delivery', label: this.$tc('sw-order.stateHistoryModal.column.delivery') },
123
                { property: 'order', label: this.$tc('sw-order.stateHistoryModal.column.order') },
124
            ];
125
        },
126
    },
127
128
    created() {
129
        this.createdComponent();
130
    },
131
132
    methods: {
133
        createdComponent(): void {
134
            void this.loadHistory();
135
        },
136
137
        async loadHistory(): Promise<void> {
138
            this.statesLoading = true;
139
140
            try {
141
                await this.getStateHistoryEntries();
142
            } catch (error: unknown) {
143
                // @ts-expect-error
144
                // eslint-disable-next-line max-len
145
                // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
146
                const errorMessage = error?.response?.data?.errors?.[0]?.detail || '';
147
148
                this.createNotificationError({
149
                    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
150
                    message: errorMessage,
151
                });
152
            } finally {
153
                this.statesLoading = false;
154
            }
155
        },
156
157
        getStateHistoryEntries(): Promise<EntityCollection<'state_machine_history'>> {
158
            return this.stateMachineHistoryRepository.search(this.stateMachineHistoryCriteria)
159
                .then((fetchedEntries) => {
160
                    this.dataSource = this.buildStateHistory(fetchedEntries);
161
                    this.total = fetchedEntries.total ?? 1;
162
                    return Promise.resolve(fetchedEntries);
163
                });
164
        },
165
166
        buildStateHistory(allEntries: EntityCollection<'state_machine_history'>): StateMachineHistoryData[] {
167
            const states = {
168
                order: allEntries.filter((entry) => {
169
                    return entry.entityName === 'order';
170
                })[0]?.fromStateMachineState ?? this.order.stateMachineState,
171
                order_transaction: allEntries.filter((entry) => {
172
                    return entry.entityName === 'order_transaction';
173
                })[0]?.fromStateMachineState ?? this.order.transactions?.last()?.stateMachineState,
174
                order_delivery: allEntries.filter((entry) => {
175
                    return entry.entityName === 'order_delivery';
176
                })[0]?.fromStateMachineState ?? this.order.deliveries?.first()?.stateMachineState,
177
            };
178
179
            const entries = [] as Array<StateMachineHistoryData>;
180
181
            if (this.page === 1) {
182
                // @ts-expect-error - states exists
183
                // Prepend start state
184
                entries.push(this.createEntry(states, this.order));
185
            }
186
187
            allEntries.forEach((entry: Entity<'state_machine_history'>) => {
188
                // @ts-expect-error - the entityName have to be order, order_transaction or order_delivery
189
                states[entry.entityName] = entry.toStateMachineState;
190
                // @ts-expect-error - states exists
191
                entries.push(this.createEntry(states, entry));
192
            });
193
194
            return entries;
195
        },
196
197
        createEntry(
198
            states: CombinedStates,
199
            entry: Entity<'state_machine_history'> | Entity<'order'>,
200
        ): StateMachineHistoryData {
201
            return {
202
                order: states.order,
203
                transaction: states.order_transaction,
204
                delivery: states.order_delivery,
205
                createdAt: 'orderDateTime' in entry ? entry.orderDateTime : entry.createdAt,
206
                user: 'user' in entry ? entry.user : undefined,
207
                entity: 'entityName' in entry ? entry.entityName : 'order',
208
            };
209
        },
210
211
        getVariantState(entity: string, state: Entity<'state_machine_state'>): string {
212
            // eslint-disable-next-line max-len
213
            // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-return
214
            return this.stateStyleDataProviderService
215
                .getStyle(`${entity}.state`, state.technicalName).variant;
216
        },
217
218
        onClose(): void {
219
            this.$emit('modal-close');
220
        },
221
222
        onPageChange({ page, limit }: { page: number, limit: number }): void {
223
            this.page = page;
224
            this.limit = limit;
225
226
            void this.loadHistory();
227
        },
228
    },
229
});
230